package com.bjpowernode.dataservice.impl;

import com.bjpowernode.common.P2PKey;
import com.bjpowernode.mapper.FinanceAccountMapper;
import com.bjpowernode.mapper.UserMapper;
import com.bjpowernode.model.FinanceAccount;
import com.bjpowernode.model.User;
import com.bjpowernode.service.UserService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 服务提供者
 */
@DubboService(interfaceClass = UserService.class)
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private FinanceAccountMapper financeAccountMapper;

    /**
     * 统计注册用户数
     * 思路：
     * 把注册的用户数，放到redis缓存起来，在yml配置文件中配置redis端口和ip
     * 产品经理要求20分钟刷新一次数据：
     * 获取数据的过程：
     * 1.先查redis数据
     * 有数据，直接返回给请求方
     * 没有数据，查询数据库，获取最新数据，并将数据存放到redis
     * 2.设置key的存活时间为20分钟
     * <p>
     * 方法一：在主方法上，public后面加synchronized,方法同步，保证多线程情况下也是一一执行，存取表现为一致性（原子性），可是效率低下
     * 方法二
     *
     * @return
     */
    @Override
    public int countRegistryUser() {

        //获取操作string的类
        ValueOperations valueOperations = redisTemplate.opsForValue();

        //1.先查redis数据
        Integer users = (Integer) valueOperations.get(P2PKey.P2P_REGISTER_USER_COUNT);
        if (users == null) {
            synchronized (this) {
                //两个线程t1,t2,当t1走到同步块里面，还没有将数据库数据放到redis时，t2也来了，这时需要t2
                //等待t1执行完毕，将数据存到redis之后，t2再继续，这样就可以在redis拿到数据，不然高并发的集显情况下
                //可能有多个线程同时访问，在redis都拿不到数据并多次查询数据库、多次添加数据到redis中。
                users = (Integer) valueOperations.get(P2PKey.P2P_REGISTER_USER_COUNT);
                if (users == null) {
                    //2.redis没有数据，查询数据库，获取最新数据
                    users = userMapper.selectCountUser();
                    //3.把数据的查询结果存放到redis，设置key的存活时间为20分钟
                    valueOperations.set(P2PKey.P2P_REGISTER_USER_COUNT, users, 20, TimeUnit.MINUTES);
                }
            }
        }
        return users;
    }

    /**
     * 查询手机号对应的User
     */
    @Override
    public User queryByPhone(String phone) {
        User user = null;
        if (phone != null) {
            user = userMapper.selectUserByPhone(phone);
        }
        return user;
    }

    /**
     * 注册功能
     *
     * @param phone
     * @param pwd
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public User register(String phone, String pwd) {
        //1.查询phone是否注册过
        User user = userMapper.selectUserByPhone(phone);
        if (user == null) {
            //2.创建u_user的账户
            user = new User();
            user.setPhone(phone);
            user.setLoginPassword(pwd);
            user.setAddTime(new Date());
            int rows = userMapper.insertRegisterUser(user);
            if (rows < 1) {
                //注册失败
                throw new RuntimeException("注册用户，添加新用户失败");
            }

            //注册成功，添加用户到u_fiance_account,金额888
            FinanceAccount account = new FinanceAccount();
            account.setUid(user.getId());
            account.setAvailableMoney(new BigDecimal("888"));
            rows = financeAccountMapper.insert(account);
            if (rows < 1) {
                throw new RuntimeException("注册用户，添加资金账户失败");
            }
        }
        return user;
    }

    /**
     * 更新用户的idCard和name
     *
     * @param user
     * @return
     */
    @Override
    public int modifyUser(User user) {
        int rows = userMapper.updateUserIdCardName(user);
        return rows;
    }

    /**
     * 登录
     *
     * @param phone
     * @param password
     * @return
     */
    @Override
    public User login(String phone, String password) {

        User user = null;
        if (phone != null && password != null) {
            user = userMapper.selectByPhoneAndPassword(phone, password);

            if (user!=null){
                user.setLastLoginTime(new Date());
                int rows = userMapper.updateLoginTime(user);
            }
        }
        return user;
    }
}
